package com.vader.boot.applicationContext;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;

/**
 * @author Vader
 * @date 2022/3/23
 **/
@Slf4j
public class TestBeanFactory {

    public static void main(String[] args) {
        DefaultListableBeanFactory listableBeanFactory = new DefaultListableBeanFactory();

        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
                .setScope("singleton").getBeanDefinition();
        log.info("A01Application_info:{}", beanDefinition);

        listableBeanFactory.registerBeanDefinition("config", beanDefinition);
        String[] beanDefinitionNames = listableBeanFactory.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            log.info(beanDefinitionName);
        }
        log.info("------------");
        AnnotationConfigUtils.registerAnnotationConfigProcessors(listableBeanFactory);
        beanDefinitionNames = listableBeanFactory.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            log.info(beanDefinitionName);
        }

        //提供beanFactory 后处理器的主要功能并
        listableBeanFactory.getBeansOfType(BeanFactoryPostProcessor.class)
                .values().forEach(beanFactoryPostProcessor -> beanFactoryPostProcessor.postProcessBeanFactory(listableBeanFactory));

        //Bean后处理器 针对Bean的生命周期的各个阶段提供拓展
        listableBeanFactory.getBeansOfType(BeanPostProcessor.class)
                .values()
                .stream()
//                .sorted(listableBeanFactory.getDependencyComparator())
                .forEach(beanPostProcessor -> {
                    log.info(beanPostProcessor.toString());
                    listableBeanFactory.addBeanPostProcessor(beanPostProcessor);
                });

        log.info("------------");
        beanDefinitionNames = listableBeanFactory.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            log.info(beanDefinitionName);
        }

        log.info("------------");

        Inter bean3 = listableBeanFactory.getBean(Bean1.class).getInter();
        log.info("getBean3:{}", bean3);

    }

    @Configuration
    static class Config {

        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }

        @Bean
        public Bean3 bean3() {
            return new Bean3();
        }

        @Bean
        public Bean4 bean4() {
            return new Bean4();
        }

    }

    interface Inter {
    }

    public static class Bean3 implements Inter {
    }

    public static class Bean4 implements Inter {
    }

    private static class Bean1 {

        public Bean1() {
            log.info("getBean1");
        }

        @Resource
        private Bean2 bean2;

        public Bean2 getBean2() {
            return bean2;
        }

        @Autowired
        @Resource(name = "bean4")
        private Inter bean3;


        public Inter getInter() {
            return bean3;
        }

    }

    private static class Bean2 {
        public Bean2() {
            log.debug("construct_bean2");
        }
    }
}
